package cn.sinobest.pid.common.utils;

import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

import org.pentaho.di.core.Const;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.database.Database;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.encryption.Encr;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleSecurityException;
import org.pentaho.di.repository.IUser;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.repository.RepositoryMeta;
import org.pentaho.di.repository.RepositorySecurityManager;
import org.pentaho.di.repository.RepositorySecurityProvider;
import org.pentaho.di.repository.UserInfo;
import org.pentaho.di.repository.kdr.KettleDatabaseRepository;
import org.pentaho.di.repository.kdr.KettleDatabaseRepositoryMeta;
import org.pentaho.di.repository.kdr.KettleDatabaseRepositorySecurityProvider;
import org.pentaho.di.repository.kdr.delegates.metastore.KettleDatabaseRepositoryMetaStore;

import cn.com.hnisi.framework.util.Configuration;
import cn.sinobest.pid.common.AppConstant;
import cn.sinobest.pid.common.exception.MCenterException;
import cn.sinobest.pid.common.jdbc.inter.IJdbcService;

/**
 * 单例化资源库，应用启动时加载
 * @author wuxinxue
 * @time 2015-6-10 上午8:54:17
 * @copyright hnisi
 */
public class RepositoryUtil {
	
	/**
	 * 资源库元信息
	 */
	private static RepositoryMeta repositoryMeta = null;
	
	/**
	 * 资源库map
	 */
	private static Map<String, KettleDatabaseRepository> repMap = new HashMap<String, KettleDatabaseRepository>();

	/**
	 * 默认资源库
	 */
	private static Repository defaultRepository;

	/**
	 * 实例化
	 * @throws MCenterException 
	 */
	public RepositoryUtil() throws MCenterException{
			System.setProperty("KETTLE_PLUGIN_BASE_FOLDERS", RepositoryUtil.class.getResource("/").getPath()+"/plugins,"+Const.DEFAULT_PLUGIN_BASE_FOLDERS);
			if(!KettleEnvironment.isInitialized()){
				try {
					KettleEnvironment.init(false);
				} catch (KettleException e) {
					e.printStackTrace();
					throw new MCenterException(AppConstant.SYSTEM_ERROR, "kettle环境初始化失败");
				}
			}
			
			String driver = Configuration.getInstance().getValue("db_driverClassName");
			String url = Configuration.getInstance().getValue("db_url");
			String user = Configuration.getInstance().getValue("db_username");
			String pass = Configuration.getInstance().getValue("db_password");
			if(driver.equals("dm.jdbc.driver.DmDriver")){//dm database
				String urlInfos = url.substring("jdbc:dm://".length());
				int portIndex = urlInfos.indexOf(":");
				int serverIndex = urlInfos.indexOf("/");
				String dbhost = urlInfos.substring(0, portIndex);
				String port = urlInfos.substring(portIndex+1, serverIndex);
				String db = urlInfos.substring(serverIndex+1);
				
				DatabaseMeta databaseMeta = new DatabaseMeta("Kettle", "ORACLE", "Native", dbhost, db, port, user, pass);
				repositoryMeta = new KettleDatabaseRepositoryMeta("Kettle","Kettle","Kettle",databaseMeta);
			} else {
				int index = url.indexOf("/");
				if(index > 0 ){
					char last = url.charAt(index-1);
					if( last != ':' )	url = url.replaceFirst("/", ":/");
		        }
				String[] urlInfos = url.split(":");
				if(urlInfos==null||urlInfos.length<6){
					System.out.println("repository url is wrong!");
					return;
				}
				String dbhost = urlInfos[3].substring(1);
				String port = urlInfos[4];
				String db = urlInfos[5];
				
				DatabaseMeta databaseMeta = new DatabaseMeta("Kettle", "ORACLE", "Native", dbhost, db, port, user, pass);
				repositoryMeta = new KettleDatabaseRepositoryMeta("Kettle","Kettle","Kettle",databaseMeta);
			}
	}
	
	/**
	 * 添加用户的资源库信息
	 * @param userName
	 * @param userPass
	 * @return
	 * @throws KettleException 
	 * @throws KettleSecurityException 
	 * @throws SQLException 
	 */
	public static void addRepository(String userName, String userPass, IJdbcService jdbcService) throws Exception{
		KettleDatabaseRepository repository = repMap.get(userName);
		if(repository ==null ){
			repository = repositoryLogin(userName, userPass, jdbcService);
			repMap.put(userName, repository);
		}
	}
	
	private static KettleDatabaseRepository repositoryLogin(String userName, String userPass, IJdbcService jdbcService) throws Exception {
		KettleDatabaseRepository repository = new KettleDatabaseRepository();
		repository.init(repositoryMeta);
		Database database = repository.connectionDelegate.getDatabase();
		database.setConnection(jdbcService.getJdbcTemplate().getDataSource().getConnection());
		repository.connectionDelegate.setDatabase(database);
		IUser userinfo = repository.userDelegate.loadUserInfo(new UserInfo(), userName, userPass);
		KettleDatabaseRepositorySecurityProvider securityProvider = new KettleDatabaseRepositorySecurityProvider( repository, repositoryMeta, userinfo );
		repository.setSecurityProvider(securityProvider);

		repository.registerRepositoryService( RepositorySecurityProvider.class, securityProvider );
		repository.registerRepositoryService( RepositorySecurityManager.class, securityProvider );

		repository.connectionDelegate.closeReadTransaction();
		repository.metaStore = new KettleDatabaseRepositoryMetaStore( repository );
		repository.setConnected(true);
		return repository;
	}

	/**
	 * 获取用户的资源库信息
	 * @param userId
	 * @return
	 * @throws KettleException 
	 */
	public static Repository getUserRepository(String userName) throws MCenterException{
		Repository repository = repMap.get(userName);
		if(repository==null){
			throw new MCenterException(AppConstant.AUTH_INVALID, "获取用户登录信息失败，请重新登录");
		}
		return repository;
	}
	
	/**
	 * 系统内部用户的获取资源库(有密码)
	 * @param userId
	 * @return
	 * @throws MCenterException 
	 * @throws Exception 
	 */
	public static Repository innerSysUserGetRepository(String userName, String userPass, IJdbcService jdbcService) throws MCenterException {
		KettleDatabaseRepository repository = repMap.get(userName);
		if(repository == null ){
			try {
				repository = repositoryLogin(userName, userPass, jdbcService);
				repMap.put(userName, repository);
			} catch (Exception e) {
				throw new MCenterException(AppConstant.SYSTEM_ERROR, "该用户信息无可用资源库连接权限！");
			}
		}
		return repository;
	}

	/**
	 * 系统内部用户的获取资源库(无密码)
	 * @param userId
	 * @return
	 * @throws SQLException 
	 */
	public static Repository innerSysUserGetRepositoryNoPass(IJdbcService jdbcService, String userName)throws MCenterException{
		KettleDatabaseRepository repository = repMap.get(userName);
		if(repository == null ){
			try {
				String querySql = "SELECT RU.PASSWORD FROM R_USER RU WHERE RU.\"LOGIN\"=?";
				Map userInfo = jdbcService.queryForSingle(querySql, new String[]{userName}, new int[]{Types.VARCHAR});
				if(userInfo!=null){
					String userPass = (String) userInfo.get("PASSWORD");
					repository = repositoryLogin(userName, Encr.decryptPassword(userPass), jdbcService);
					repMap.put(userName, repository);
				} else {
					throw new MCenterException(AppConstant.SYSTEM_ERROR, "此用户无可用资源库连接权限！");
				}
			} catch (Exception e) {
				throw new MCenterException(AppConstant.SYSTEM_ERROR, "此用户信息无可用资源库连接权限！");
			}
		}
		return repository;
	}
	
	/**
	 * 获取用户的资源库信息
	 * @param userId
	 * @return
	 */
	public static Repository getRepositoryPerJobId(IJdbcService jdbcService, String jobId) throws MCenterException {
		String querySql = "SELECT VRJ.MODIFIED_USER, RU.PASSWORD FROM V_R_JOB VRJ, R_USER RU WHERE VRJ.MODIFIED_USER=RU.\"LOGIN\" AND VRJ.ID_JOB=?";
		Map userInfo = jdbcService.queryForSingle(querySql, new String[]{jobId}, new int[]{Types.VARCHAR});
		if(userInfo == null || userInfo.size()==0 ) {
			throw new MCenterException(AppConstant.SYSTEM_ERROR, "无法通过作业获取用户信息！");
		}
		
		String userName = (String) userInfo.get("MODIFIED_USER");
		String userPass = (String) userInfo.get("PASSWORD");
		return innerSysUserGetRepository(userName, Encr.decryptPassword(userPass), jdbcService);
	}
	
	public static RepositoryMeta getRepositoryMeta() {
		return repositoryMeta;
	}

	public static Repository getInstance(IJdbcService jdbcService) throws Exception {
		if(defaultRepository!=null){
			try {
				String querySql = "SELECT RU.PASSWORD FROM R_USER RU WHERE RU.\"LOGIN\"=?";
				Map userInfo = jdbcService.queryForSingle(querySql, new String[]{AppConstant.REPOSITORY_ROOT_NAME}, new int[]{Types.VARCHAR});
				if(userInfo!=null){
					String userPass = (String) userInfo.get("PASSWORD");
					defaultRepository = repositoryLogin(AppConstant.REPOSITORY_ROOT_NAME, Encr.decryptPassword(userPass), jdbcService);
				} else {
					throw new MCenterException(AppConstant.SYSTEM_ERROR, "资源库的root用户已被删除！");
				}
			} catch (Exception e) {
				throw new MCenterException(AppConstant.SYSTEM_ERROR, "资源库连接失败！");
			}
		}
		return defaultRepository;
	}
}